package General;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.Observable;
import java.util.Observer;

import javax.imageio.ImageIO;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.GrayFilter;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

import Card.Card;
import Card.GatherCard;

import sun.audio.AudioData;
import sun.audio.AudioPlayer;
import sun.audio.AudioStream;
import sun.audio.ContinuousAudioDataStream;

public class Game7 extends JPanel implements ActionListener,Observer {
	JButton b1,b2,b3,b4,b5,b6,b7;
    public static JTextArea textarea;
    public static JScrollPane scroller;
    private Image bgimage;
    
    private int playerCount;
    Player[] players;    	//Need some container to hold players
    Bank bank;            	//The central bank, holds resources to be circulated
    public static GUI currentUI;	//black boxing can suck it
    public static Game7 currentGame;	//screw black boxing
    public static final boolean UI = false;            //false for CLI, true for GUI
    public static final int MIN_PLAYERS = 2;
    public static final int MAX_PLAYERS = 9;
    public static final int NO_ROW=28;
    public static boolean victory = false;            //global flag, when set game will halt next cycle
    private int currentPlayer=0;
    //private int startingPlayer=0;
    private int startingPlayer;

    public static void startMusic() throws IOException { 
    	InputStream in = null;
        AudioStream audioStream = null;
        AudioData audioData;
        ContinuousAudioDataStream loop = null;
    	try {
    		in = new FileInputStream("res/sound.wav");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        try {
        	audioStream = new AudioStream(in);
            audioData = audioStream.getData();
            loop = new ContinuousAudioDataStream(audioData);
        } catch (IOException e) {
            e.printStackTrace();
        }
        AudioPlayer.player.start(loop);
//        AudioPlayer.player.stop(audioStream);
    }
    
	//constructor
	public Game7() throws IOException, UnsupportedAudioFileException, LineUnavailableException{
		startMusic();
		JFrame frame = new JFrame("Age of Mythology");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setSize(800,600);
		frame.setLocation(300,100);
		
		JPanel panel = new JPanel();
		
		JButton b1=new JButton("Explore");
		b1.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent ae){
				JOptionPane.showMessageDialog(null, "Explore");
			}
		});
		JButton b2=new JButton("Gather");
		JButton b3=new JButton("Build");
		JButton b4=new JButton("Recruit");
		JButton b5=new JButton("Trade");
		JButton b6=new JButton("Next Age");
		JButton b7=new JButton("Attack");
		panel.add(b1);
		panel.add(b2);
		panel.add(b3);
		panel.add(b4);
		panel.add(b5);
		panel.add(b6);
		panel.add(b7);
		
		final ImageIcon icon = new ImageIcon("res/bg3.jpg");
		JLabel label = new JLabel(icon);
		textarea = new JTextArea(){
		      Image grayImg = GrayFilter.createDisabledImage(icon.getImage());{
		        setOpaque(false);
		      }
		      public void paint(Graphics g) {
		        g.drawImage(grayImg, 0, 0, this);
		        super.paint(g);
		      }
		    };
		textarea.setEditable(false);
		Font font = new Font("Courier", Font.PLAIN, 13);
		textarea.setFont(font);
		textarea.setForeground(Color.yellow);
//		scroller = new JScrollPane(textarea);
		frame.getContentPane().add(label);

		frame.getContentPane().add(BorderLayout.NORTH,panel);
//		frame.getContentPane().add(BorderLayout.CENTER,scroller);
		frame.getContentPane().add(BorderLayout.CENTER,textarea);
		frame.setVisible(true);
	}

	public static void displayText(String myString){
		if (textarea.getLineCount()>NO_ROW-5)
		textarea.setText("");
		textarea.append(myString + "\n");
	}
	
	public void actionPerformed(ActionEvent arg0) {
		// TODO Auto-generated method stub
		
	}
	
	public static void main(String[] args){
	      javax.swing.SwingUtilities.invokeLater(new Runnable() {
	    	  public void run() {
	    		  try {
	    			  Game7.currentGame = new Game7();
	    			  Game7.currentUI = new GUI();
	    			  Game7.currentUI.programIntro(); 	//Displays purpose of the program
	    			  // Setup players
	    		      Culture.initializeCard();
	    		      Game7.currentGame.requestPlayers();
	    		      Game7.currentGame.bank = Bank.createBank(Game7.currentGame.playerCount);
	    			  Bank.singletonBank.addObserver(Game7.currentGame);
	    			  Game7.currentGame.initializePlayers();
	    			  Game7.currentGame.runGame(Game7.currentGame);
	    		  } catch (IOException e) {
	    			  // TODO Auto-generated catch block
	    			  e.printStackTrace();
	    		  } catch (UnsupportedAudioFileException e) {
	    			  // TODO Auto-generated catch block
	    			  e.printStackTrace();
	    		  } catch (LineUnavailableException e) {
	    			  // TODO Auto-generated catch block
	    			  e.printStackTrace();
	    		  }
	    	  }
	      });
    }//end main
	
    public void runGame(Game7 currentGame){
    	startingPlayer = Dice.determineStarting(playerCount);
		int mode=-1;
		do{
			switch(mode){
			case -1: //testing
				//startingPlayer = Dice.determineStarting(playerCount);
				currentPlayer = startingPlayer;
				//new GatherCard(null,false).use(players[currentPlayer]);
				displayText(currentUI.drawPlayer(players[currentPlayer]));
				mode++;
				break;
			case 0:	// assign victory points
				currentPlayer = startingPlayer;
				int	end = playerCount==2?2:3;	//if there are only 2 players only assign 2 pts 
				for(int i =0; i<end; i++){
					Bank.singletonBank.placeVictory(
							VictoryCards.fromInt(
									currentUI.assignVictory(
											this.players[currentPlayer])));
			    	String[] menuOptions = new String[VictoryCards.values().length];
			    	
			    	int j = 0;
			    	for(VictoryCards cards: VictoryCards.values()){
			    		menuOptions[j] = cards.toString()+": "
			    		+Bank.singletonBank.getVictory(cards);
			    		Game7.displayText(menuOptions[j]);
			    		j++;
			    	}
			    	
			    	
					nextPlayer();
				}
				mode++;
				break;
			case 1:
				//Draw Action cards
				currentPlayer = startingPlayer;
				for(int i = 0; i < playerCount; i++){
					int currentCard=0;
					boolean drawComplete = false;
					boolean randMode= false;
					while(!drawComplete){
						if(!players[currentPlayer].handFull()){	//check to see if player can draw
							if(!randMode){
								currentCard= currentUI.drawCard(players[currentPlayer]);
								//currentUI.drawCard(players[currentPlayer]); 
								currentCard -=1;	//account for the display-backend numbering scheme disparity;
							}else {
								currentCard= currentUI.drawRandom(players[currentPlayer]);
								currentCard = currentCard==0?-1:7;	//choices are limited to -1 random, 7 pass
							}
							
							if(currentCard ==-1){	//whenever a random card is drawn state changes to random only
								randMode= true;
								players[currentPlayer].draw(currentCard);
							} else if(currentCard == 7){	//player wishes to pass
								if(players[currentPlayer].handCount()<3){
									currentUI.notifyEmptyHand(players[currentPlayer]);
								} else drawComplete = true;
							} else {	//normal card drawing procedure
								players[currentPlayer].draw(currentCard);
							}
						}else {
							currentUI.notifyFullHand(players[currentPlayer]);
							drawComplete = true;
						}
//						currentUI.padOut();
					}
					nextPlayer();
				}
				currentUI.displayHand(players[currentPlayer]);
				mode++;
				break;
			case 2:	//Action card play
				currentPlayer= startingPlayer;
				for(int round = 0; round< 3; round++){	//start of action card play
					Integer choice;
					for(int turn = 0; turn<3; turn++){
						displayText(currentUI.drawPlayer(players[currentPlayer]));
						choice = currentUI.useHand(players[currentPlayer]);
						if(choice!=null){
							players[currentPlayer].playHand(choice.intValue());
						}
						nextPlayer();
					}
				}
				//Don't forget to implement a bonus round
				mode++;				
				break;
				
			case 3: // Spoilage
				currentPlayer= startingPlayer;
				for(int i = 0; i< playerCount; i++){
					Resource before = players[currentPlayer].getWallet().getFunds();
					players[currentPlayer].spoil();
					Resource after = players[currentPlayer].getWallet().getFunds();
//					currentUI.spoilage(players[currentPlayer], before, after);
					nextPlayer();
				}
				mode++;
				break;
			case 4: // Discard
				currentPlayer = startingPlayer;
				for(int i = 0; i< playerCount; i++){
					boolean done = players[currentPlayer].handCount()==0;;
					Integer choice;
					while(!done && players[currentPlayer].handCount()>0){
						choice = currentUI.discardHand(players[currentPlayer]);
						if(choice ==null){
							done = true;
						} else{
							players[currentPlayer].discard(choice.intValue());
						}
					}
					nextPlayer();
				}
				mode++;
				break;
			case 5:	// Rotate Player
				rotateStarting();
				mode = 0;
			default: //In case an option not listed is selected
				System.out.println("Bad Game State");
				victory= true;
				break;
			}	//end switch
			
		}while (Game.victory==false);
			
    }//end runGame
    
    public int getPlayerCount()
    {
        return playerCount;
    }//end getPlayerCount
   
    private void setPlayerCount(int players)
    {
        playerCount=players;
        displayText("Number of Players is: " + Integer.toString(playerCount));
    }//end setPlayercount
   
    private void requestPlayers()
    {
        setPlayerCount(currentUI.getBoundedInt("Number of players: ",2,8));
    }//end request Players
   
   
    private void initializePlayers(){
        int count = getPlayerCount();
        String name= null;
        players = new Player[count];
        LinkedList<Integer> cultures = Dice.chooseCulture(count);
        int index = 0;
        while(!cultures.isEmpty() && index < count){    //copy values to array
            players[index] = new Player(cultures.pop());
            name = JOptionPane.showInputDialog("State your name Player " + index + ": ");
            players[index].setName(name);
            displayText("Player " + index + "'s name: " + name);
            index++;
        }//end while-loop
    }//end initialize players
   
   

    public void drawActionCards(Player player)
    {
       
    }//end method
   
   
    public void setVictory(){
        victory= true;
    }
    
    private void nextPlayer(){
    	currentPlayer= (currentPlayer + 1)%playerCount;
    }
    private void rotateStarting(){
    	startingPlayer = (startingPlayer +1)%playerCount;
    }
    /**
     * This observer observes the value of the victory points left in the bank.  
     * If the bank runs out of victory points, the game is over 
     */
	  
	public void update(Observable o, Object arg) {
	// TODO not enought time to implement proper generics/ type safety 
		Integer a = (Integer)arg;
		if (a.compareTo(new Integer(0))<=0){
			victory= true;
		}
	}
	
	protected void paintComponent(Graphics g) {
	    super.paintComponent(g);
	    int imwidth = bgimage.getWidth(null);
	    int imheight = bgimage.getHeight(null);
	    g.drawImage(bgimage, 1, 1, null);
	}
	public GUI getCurrentUI(){
		return this.currentUI;
	}

	public void explore(int count) {
		// TODO Auto-generated method stub
		LinkedList<Tile> tiles = new LinkedList<Tile>();
		for(int i = 0; i<count+playerCount; i++){
			tiles.add(Bank.singletonBank.getTile());
		}
		for(int i = 0; i< playerCount; i++){
			Game7.displayText(currentUI.drawProductionArea(players[currentPlayer]));
			Tile selection = currentUI.explore(players[currentPlayer], tiles.toArray(new Tile[tiles.size()]));			
			boolean mainLoop = selection==null;	//if not null enter loop else don't try;
			while(!mainLoop){
				if(selection == null){
					nextPlayer();//player Passed
				}else {
					boolean correct= false;
					//boolean holdTile = false;
					Integer x;
					Integer y;
					while(correct == false){
						x = currentUI.getX(players[currentPlayer],selection);
						y = currentUI.getY(players[currentPlayer],selection);
						if(x==null || y == null){
							correct = true;	//exit miniloop not main
							mainLoop = true;	//exit mainloop
						}else 
						if(players[currentPlayer].attachTile(x,y,selection)){
							Game7.displayText(currentUI.drawProductionArea(players[currentPlayer]));
							nextPlayer();
							correct = true;
							mainLoop = true;
							//holdTile = true;
						} else {
							System.out.println(selection + "x: "+x+"y: "+y+" "+players[currentPlayer].getTerrain(x, y));
						}
					}
					if(mainLoop) tiles.remove(selection);	//if we're done remove tile
					//holdTile = false;
				}
			}
		}
		//Cleanup
		while(!tiles.isEmpty()){
			Bank.singletonBank.rePoolTile(tiles.pop());	
		}
	}
	public void recruit(int recruits, General.Player owner) 
	{
		int recruitees=0;
		int unitPick=0;
		int culture= owner.getCulture();
//		recruitees= Game7.currentUI.getBoundedInt("How many units you finna recruit boy-o?", 0, 6);
//		if (recruitees>recruits)
//			displayText("Pump the brakes");
//		else
//			for(int i=0; i<=recruitees; i++)
//	    	{
				unitPick= Game7.currentUI.recruitCards(culture);
//				displayText("That's cool brah, pick some moar. Unless you shouldn't...in which case you should pump the brakes");
				owner.getBoard().recruit(Unit.getUnit(culture)[unitPick]); 
//	    	}
			
		
	}
	public boolean trade(boolean type){ //true for random action card, false for permanent card
		//TODO need to implement the victory trade
		int[] resourceToBank = new int[4];
		int[] resourceToPlayer = new int[4];
		boolean noProblem;
		int amount;
			
		int cubeType;
		int tradeType = currentUI.getBoundedInt("Which resource do you have to trade?" +
				"\n0:Food, 1:Wood, 2:Favor, 3:Gold, 4:Victory Point",0,4);
		amount = currentUI.getBoundedInt("How much do you want to trade?",1,30);
		//11 = Great Temple building to allow victory pt trading.
		if ((tradeType==4)&&players[currentPlayer].getBoard().buildings.searchOtherBuildings(11)){
			noProblem = players[currentPlayer].getWallet().pay(
					new General.Resource(0,0,amount*8,0),Bank.singletonBank.getWallet());
			if (noProblem) Bank.singletonBank.purchaseVictory(amount,players[currentPlayer]);
		}
		else {		
			resourceToBank[tradeType] = amount;
			if (type){
				if (players[currentPlayer].getBoard().buildings.searchOtherBuildings(3))
					cubeType = 0; //cost is 0 if player has Market (3)
				else cubeType=currentUI.tradeMenuRandom(players[currentPlayer]);
				resourceToBank[tradeType] += cubeType + 1;
			}
			else {
				if (players[currentPlayer].getBoard().buildings.searchOtherBuildings(3))
					cubeType = 0; //cost is 0 if player has Market (3)
				else cubeType=currentUI.tradeMenuPernament(players[currentPlayer]);
				if (cubeType==0) resourceToBank[0] += 2;
				else if (cubeType==1) resourceToBank[1] += 2;
				else if (cubeType==2) resourceToBank[2] += 2;
				else if (cubeType==3) resourceToBank[3] += 2;
				else if (cubeType==4) {resourceToBank[0]++; resourceToBank[1]++;}
				else if (cubeType==5) {resourceToBank[0]++; resourceToBank[2]++;}
				else if (cubeType==6) {resourceToBank[0]++; resourceToBank[3]++;}
				else if (cubeType==7) {resourceToBank[1]++; resourceToBank[2]++;}
				else if (cubeType==8) {resourceToBank[1]++; resourceToBank[3]++;}
				else if (cubeType==9) {resourceToBank[2]++; resourceToBank[3]++;}
				int receiveType = currentUI.getBoundedInt("Which resource do you want to receive?" +
						"\n0:Food, 1:Wood, 2:Favor, 3:Gold",0,3);
				resourceToPlayer[receiveType] = amount;
			}
			noProblem = General.Bank.singletonBank.tradeResource(
					new General.Resource(resourceToBank[0],resourceToBank[1],resourceToBank[2],resourceToBank[3]),
					new General.Resource(resourceToPlayer[0],resourceToPlayer[1],resourceToPlayer[2],resourceToPlayer[3]),
					players[currentPlayer]);
		}
		return noProblem;
	}
	public void gather(Player player, boolean all){
		currentUI.moveVillager(player);
		if(all){
			Bank.singletonBank.getWallet().forcePay(players[currentPlayer].getBoard().gather(),players[currentPlayer].getWallet());
			nextPlayer();
		}else{
			if(currentUI.gatherType(players[currentPlayer])){//resource type
				Resources res = currentUI.selectResource(players[currentPlayer]);
				Bank.singletonBank.getWallet().forcePay(players[currentPlayer].getBoard().gather(res),players[currentPlayer].getWallet());
			}else {//terrain type
				Terrain ter = currentUI.selectTerrain(players[currentPlayer]);
				Bank.singletonBank.getWallet().forcePay(players[currentPlayer].getBoard().gather(ter),players[currentPlayer].getWallet());
			}
		}
		
	}
	public boolean build(int maxBuilding, boolean type){
		boolean noProblem;
		int howmany;
		Resource newResource = new Resource(0,0,0,0,0);
		howmany = currentUI.getBoundedInt("How many buildings do you want to build?"+
				"\nMaximum is: "+ maxBuilding,1,maxBuilding);
		for (int i=0;i<maxBuilding;i++){
			int whichBuilding = currentUI.buildMenu();
			if (whichBuilding==13){
				noProblem = players[currentPlayer].getWallet().pay(new General.Resource (2,2,0,0,0),Bank.singletonBank.getWallet());
				if (noProblem)
					players[currentPlayer].getBoard().buildings.buildHouse(1);
				else return false;
			}
			else {
				if ((whichBuilding==0)||(whichBuilding==1)) newResource=new Resource (0,3,0,3,0);
				else if (whichBuilding==2) newResource=new Resource (2,2,2,2,0);
				else if (whichBuilding==3) newResource=new Resource (0,0,2,3,0);
				else if (whichBuilding==4) newResource=new Resource (0,3,0,2,0);
				else if (whichBuilding==5) newResource=new Resource (4,0,0,1,0);
				else if (whichBuilding==6) newResource=new Resource (3,0,0,2,0);
				else if (whichBuilding==7) newResource=new Resource (0,2,0,3,0);
				else if (whichBuilding==8) newResource=new Resource (3,2,0,0,0);
				else if (whichBuilding==9) newResource=new Resource (2,0,0,3,0);
				else if (whichBuilding==10) newResource=new Resource (0,3,0,2,0);
				else if (whichBuilding==11) newResource=new Resource (4,4,4,4,0);
				else if (whichBuilding==12) newResource=new Resource (10,10,10,10,0);

				noProblem = players[currentPlayer].getWallet().pay(newResource,Bank.singletonBank.getWallet());
				if (noProblem)
					players[currentPlayer].getBoard().buildings.buildotherBuilding(whichBuilding);
				else return false;
			}
		}
		displayText("Buildings: \n"+players[currentPlayer].getBoard().buildings.toString());
		return true;
	}
}
